﻿using System;
using System.Windows;
using System.Windows.Controls;
using BrainTechLLC;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using BrainTechLLC.Silverlight.Controls;
using System.Threading;

namespace BrainTechLLC.Silverlight.ClientApplication
{
    public partial class ShowLocationsControl : BaseDataVisualizer, ICollectionDataVisualizer
    {
        public static int showX = 10;
        public static int showY = 10;
        public static int showZ = 10;

        public override void SetVisualizedData(DataVisualizer vis, object o) {  Locations = o as ObservableCollection<GameLocation>; base.SetVisualizedData(vis, o); }
        public Type VisualizeType { get { return typeof(GameLocation); } }
        public string VisualizerName { get { return "ShowLocationsControl"; } }

        public static void HandleChange<T2>(DependencyObject d, DependencyPropertyChangedEventArgs e, Action<ShowLocationsControl, T2> action)
        {
            d.HandleChange<ShowLocationsControl, T2>(e, action, (t) => t.UpdateBindings());
        }

        public static readonly DependencyProperty LocationsProperty = DependencyProperty.Register(
            "Locations", typeof(ObservableCollection<GameLocation>), typeof(ShowLocationsControl), new PropertyMetadata(null, new PropertyChangedCallback(LocationsChanged)));

        public static readonly DependencyProperty XProperty = DependencyProperty.Register(
            "X", typeof(int), typeof(ShowLocationsControl), new PropertyMetadata(4, new PropertyChangedCallback(XChanged)));

        public static readonly DependencyProperty YProperty = DependencyProperty.Register(
            "Y", typeof(int), typeof(ShowLocationsControl), new PropertyMetadata(4, new PropertyChangedCallback(YChanged)));

        public static readonly DependencyProperty ZProperty = DependencyProperty.Register(
            "Z", typeof(int), typeof(ShowLocationsControl), new PropertyMetadata(1, new PropertyChangedCallback(ZChanged)));

        public ObservableCollection<GameLocation> Locations
        {
            get { return (ObservableCollection<GameLocation>)GetValue(LocationsProperty); }
            set { SetValue(LocationsProperty, value); }
        }

        private static void LocationsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<ObservableCollection<GameLocation>>(d, e, (t, val) => t.Locations = val);
        }

        public int X
        {
            get { return (int)GetValue(XProperty); }
            set { SetValue(XProperty, value); }
        }

        private static void XChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<int>(d, e, (t, val) => t.X = val);
        }

        public int Y
        {
            get { return (int)GetValue(YProperty); }
            set { SetValue(YProperty, value); }
        }

        private static void YChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<int>(d, e, (t, val) => t.Y = val);
        }

        public int Z
        {
            get { return (int)GetValue(ZProperty); }
            set { SetValue(ZProperty, value); }
        }

        private static void ZChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HandleChange<int>(d, e, (t, val) => t.Z = val);
        }

        public override void UpdateBindings()
        {
            if (mainGrid != null && Locations != null)
            {
                ClearLocationsFromMainGrid();
                CreateMainGridRowColumnDefs();

                GameLocation locStart = FindLocation(X, Y, Z);
                LocationAndExitVisitor visitor = new LocationAndExitVisitor()
                {
                    MaxCoordinate = new LocationInt(showX, showY, showZ)                    
                };

                visitor.VisitingLocation += new EventHandler<VisitorEventArgs>(visitor_VisitedLocation);
                visitor.VisitingExit += new EventHandler<VisitExitEventArgs>(visitor_VisitedExit);
                visitor.RunVisitor(locStart.AssociatedID, new LocationInt(3,3,1));
                visitor.VisitingLocation -= visitor_VisitedLocation;
                visitor.VisitingExit -= visitor_VisitedExit;
                visitor = null;

                mainGrid.UpdateLayout();
            }
        }

        void visitor_VisitedExit(object sender, VisitExitEventArgs e)
        {
            DrawConnectionLine(e.Location.XYZ.X, e.Location.XYZ.Y, e.Direction);
        }

        void visitor_VisitedLocation(object sender, VisitorEventArgs e)
        {
            GameLocationVis1 vis = new GameLocationVis1();
            vis.GameLocation = e.Location;
            vis.DisplayX = e.Location.XYZ.X;
            vis.DisplayY = e.Location.XYZ.Y;

            if (e.Location.XYZ.Equals(X, Y, Z))
            {
                vis.Background = new SolidColorBrush(Color.FromArgb(255, 255, 0, 255));
            }
            else
            {
                vis.Background = new SolidColorBrush(Color.FromArgb(255, (byte)((e.XYZ.X * 7) % 255), (byte)((e.XYZ.Y * 8) % 255), 240));
            }

            vis.canvasMain.Background = vis.Background;
            vis.txtInfo.Background = vis.Background;
            vis.WantViewRoom += new EventHandler<ObjectEventArgs<GameLocation>>(vis_WantViewRoom);

            Grid.SetColumn(vis, e.XYZ.X);
            Grid.SetRow(vis, e.XYZ.Y);
            mainGrid.Children.Add(vis);
        }

        private void CreateMainGridRowColumnDefs()
        {
            for (int n = 0; n < showX; n++)
            {
                mainGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(180, GridUnitType.Pixel) });
            }
            for (int n = 0; n < showY; n++)
            {
                mainGrid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(44, GridUnitType.Pixel) });
            }
        }

        private void ClearLocationsFromMainGrid()
        {
            mainGrid.ColumnDefinitions.Clear();
            mainGrid.RowDefinitions.Clear();

            foreach (var c in mainGrid.Children)
            {
                GameLocationVis1 vis = c as GameLocationVis1;
                if (vis != null)
                {
                    vis.WantViewRoom -= vis_WantViewRoom;
                }
            }

            mainGrid.Children.Clear();
        }

        void vis_WantViewRoom(object sender, ObjectEventArgs<GameLocation> e)
        {
            editGameLocation.Visibility = Visibility.Visible;
            editGameLocation.DataToVisualize = e.obj;
            Dispatcher.BeginInvoke(() => { Thread.Sleep(2000); editGameLocation.WindowlessMode = false; });

        }

        private void DrawConnectionLine(int x, int y, GeneralDirection dir)
        {
            Rectangle r = new Rectangle()
            {
                Fill = new SolidColorBrush(Colors.Green),
                StrokeThickness = 5,
                HorizontalAlignment = HorizontalAlignment.Stretch,
                VerticalAlignment = VerticalAlignment.Stretch,
                Stroke = new SolidColorBrush(Colors.Blue),
                Stretch = Stretch.Fill
            };

            if (dir == GeneralDirection.N)
            {
                Grid.SetColumn(r, x);
                Grid.SetRow(r, y - 1);
                Grid.SetRowSpan(r, 2);
                r.Height = 40;
                r.Width = 4;
            }
            else if (dir == GeneralDirection.W)
            {
                Grid.SetColumn(r, x - 1);
                Grid.SetRow(r, y);
                Grid.SetColumnSpan(r, 2);
                r.Height = 3;
                r.Width = 60;
            }
            else if (dir == GeneralDirection.S)
            {
                Grid.SetColumn(r, x);
                Grid.SetRow(r, y);
                Grid.SetRowSpan(r, 2);
                r.Height = 40;
                r.Width = 4;
            }
            else if (dir == GeneralDirection.E)
            {
                Grid.SetColumn(r, x);
                Grid.SetRow(r, y);
                Grid.SetColumnSpan(r, 2);
                r.Height = 3;
                r.Width = 60;
            }

            Canvas.SetZIndex(r, 12);
            mainGrid.Children.Add(r);
        }

        public GameLocation FindLocation(int x, int y, int z)
        {
            for (int n = 0; n < Locations.Count; n++)
            {
                if (Locations[n].XYZ.Equals(x, y, z))
                    return Locations[n];
            }

            return null;
        }

        public ShowLocationsControl()
        {
            InitializeComponent();
        }

        private void borderEditLocation_Loaded(object sender, RoutedEventArgs e)
        {
        }

        void editLoc_WantClose(object sender, EventArgs e)
        {
            editGameLocation.Visibility = Visibility.Collapsed;
        }
    }
}